/// \file		WnTCPClient.cpp
/// \brief		WIND通信(TCP)客户端类的定义文件
/// \author		xuefeng
/// \version	1.0
/// \date		2011-07-19
/// \history	2011-07-19 新建

#include "ComHeader.h"
#include "WnTCPClient.h"
#include "WnBaseIOService.h"
#include "WnConnection.h"
using namespace boost::system;

// 读写锁
typedef boost::shared_lock<boost::shared_mutex> readLock;
typedef boost:: unique_lock<boost::shared_mutex> writeLock;

const auto MAX_CLIENT_REF_COUNTER = 2;

WnTCPClient::WnTCPClient(int id, ITCPClientNotify *poNotify, int HBInterval, unsigned short usThreadCount)
  : WnEndPoint(id)
  , m_apConnection()
  , m_poNotify(poNotify)
  , m_HB_interval(HBInterval)
{
  m_usPort = 0;
  m_blAuth = false;
  m_unTimeOut = 0;

  m_poBaseIOService = new WnBaseIOService();
  m_poBaseIOService->StartService(usThreadCount);

  m_oTimer.reset(new deadline_timer(m_poBaseIOService->GetIOService()));
  m_oTimeOutTimer.reset(new deadline_timer(m_poBaseIOService->GetIOService()));
}

WnTCPClient::~WnTCPClient(void)
{
  // 关闭socket
  CloseSocket();
  ClearNotifyObj();

  // 停止ios服务
  m_poBaseIOService->StopService();
  delete m_poBaseIOService;
}

void WnTCPClient::ConnectServer(const char *szIP, unsigned short usPort, bool blAuth, unsigned int unTimeOut)
{
  Connect(szIP, usPort, blAuth, unTimeOut);

  m_szIP = szIP;
  m_usPort = usPort;
  m_blAuth = blAuth;
  m_unTimeOut = unTimeOut;
}

bool WnTCPClient::SendDataToServer(const unsigned char *pbData, unsigned int unDataSize)
{
  return SendData(pbData, unDataSize);
}

void WnTCPClient::CloseSocket()
{
  boost::mutex::scoped_lock oLock(m_oOperateMutex);

  // 关闭自动重连标志
  SetReconnectFlag(false);

  // 取消定时器
  if(m_oTimer)
  {
    m_oTimer->cancel();
  }

  if(m_oTimeOutTimer)
  {
    m_oTimeOutTimer->cancel();
  }

  // 关闭连接
  if(m_apConnection)
  {
    m_apConnection->Close();
    m_apConnection.reset();
  }
}

void WnTCPClient::OnConnect(CONNECTION_APTR apConnection, int nStatus)
{
  //if(m_apConnection.get() == apConnection.get())
  // @revised by huang.z.d @20160516使用clientid来判断
  if(m_apConnection && apConnection && m_apConnection->clientID() == apConnection->clientID())
  {
    // 取消定时器
    m_oTimer->cancel();

    if(0 == nStatus)
    {
      m_oTimeOutTimer->expires_from_now(millisec(m_HB_interval * NO_HEARTBEAT_COUNT));
      m_oTimeOutTimer->async_wait(boost::bind(&WnTCPClient::OnNoRecvDataTimer, this, boost::asio::placeholders::error));
    }

    boost::thread(boost::bind(&WnTCPClient::OnConnectThread, this, nStatus));
	
      // auto connect
      if(E_CONNECT_SUCCESS != nStatus)
      {
        ::sleep(1); // 延时一小段时间，防止cpu被占满
        Connect(m_szIP.c_str(), m_usPort, m_blAuth, m_unTimeOut);
      }
  }
}

void WnTCPClient::OnDisconnect(CONNECTION_APTR apConnection, int nStatus)
{
  //if(m_apConnection.get() == apConnection.get())
  // @revised by huang.z.d @20160516使用clientid来判断
  if(m_apConnection && apConnection && m_apConnection->clientID() == apConnection->clientID())
  {
    m_oTimeOutTimer->cancel();

    // 短线程
    boost::thread(boost::bind(&WnTCPClient::OnDisconnectThread, this, nStatus));

    // auto connect
    Connect(m_szIP.c_str(), m_usPort, m_blAuth, m_unTimeOut);
  }
}

void WnTCPClient::OnReceiveData(CONNECTION_APTR apConnection, const PACKET_APTR& apPacket)
{
  //if(m_apConnection.get() == apConnection.get())
  // @revised by huang.z.d @20160516使用clientid来判断
  if(m_apConnection && apConnection && m_apConnection->clientID() == apConnection->clientID())
  {
    // 取消原定时器
    m_oTimeOutTimer->cancel();

    // 重启定时器
    m_oTimeOutTimer->expires_from_now(millisec(m_HB_interval * NO_HEARTBEAT_COUNT));
    m_oTimeOutTimer->async_wait(boost::bind(&WnTCPClient::OnNoRecvDataTimer, this, boost::asio::placeholders::error));

    if(apPacket->GetPacketData() != NULL)
    {
      if(!apPacket->IsHeartBeatPacket())
      {
        readLock lock(m_oNotifyMutex);
        if(m_poNotify != NULL) // 通知接收到数据
          m_poNotify->OnRecvServerData(apPacket->GetBodyData(), apPacket->GetBodyLength());
      }
      else // 心跳应答（原样发回）
        m_apConnection->AsyncSend(apPacket, true);
    }
  }
}

void WnTCPClient::OnDataError(CONNECTION_APTR apConnection)
{
  //if(m_apConnection.get() == apConnection.get())
  // @revised by huang.z.d @20160516使用clientid来判断
  if(m_apConnection && apConnection && m_apConnection->clientID() == apConnection->clientID())
  {
    // 取消原定时器
    m_oTimeOutTimer->cancel();

    // 重启定时器
    m_oTimeOutTimer->expires_from_now(millisec(m_HB_interval * NO_HEARTBEAT_COUNT));
    m_oTimeOutTimer->async_wait(boost::bind(&WnTCPClient::OnNoRecvDataTimer, this, boost::asio::placeholders::error));
  }

  boost::thread(boost::bind(&WnTCPClient::OnDataErrorThread, this));
}

void WnTCPClient::ClearNotifyObj()
{
  writeLock lock(m_oNotifyMutex);
  m_poNotify = NULL;
}

void WnTCPClient::Close()
{
  CloseSocket();
}

void WnTCPClient::Connect(const char *szIP, unsigned short usPort, bool blAuth, unsigned int unTimeOut)
{
  CloseSocket();

  boost::mutex::scoped_lock oLock(m_oOperateMutex);

  // 创建连接
  m_apConnection.reset(new WnConnection<boost::asio::ip::tcp>(shared_from_this(), m_poBaseIOService->GetIOService()));

  string strHostName;
  if(szIP != NULL)
    strHostName = szIP;

  string strPort = boost::lexical_cast<string>(usPort);

  // 设置地址端口
  int nResult = m_apConnection->SetAddr(strHostName, strPort);
  if(0 == nResult)
  {
    // 开始连接
    m_apConnection->BeginConnect();

    // 设定连接超时定时器
    if(unTimeOut != 0)
    {
      m_oTimer->expires_from_now(seconds(unTimeOut));
      m_oTimer->async_wait(boost::bind(&WnTCPClient::OnConnectTimeOutTimer, this, boost::asio::placeholders::error));
    }
  }
  else
    OnConnect(m_apConnection, E_CONNECT_ADDRERROR);
}

bool WnTCPClient::SendData(const unsigned char *pbData, unsigned int unDataSize)
{
  bool blResult = false;

  if(!m_apConnection)
    return blResult;

  if((pbData == NULL) || (unDataSize == 0))
    return blResult;

  PACKET_APTR apPacket;
  apPacket.reset(new WnPacket(pbData, unDataSize, 0, 0));

  ENU_ASYNSEND_RESULT eResult = m_apConnection->AsyncSend(apPacket, false);
  // 判断发送结果
  if(eResult != E_AR_SUCCESS)
  {
    // 发送通知
    {
      stringstream ss;
      ss << "file:" << __FILE__ << ", function:" << __FUNCTION__ << ", line:" << __LINE__ << ". @@@. "
        << "客户端数据发送错误. eResult:" << eResult;

      OnMsg(2, ss.str());
    }

    if((eResult == E_AR_NOSEND) || (eResult == E_AR_OVERFLOW))
    {
      // 关闭连接
      m_apConnection->Close();

      // 发出通知
      OnDisconnect(m_apConnection, E_DISCONNECT_IOERROR);
    }
  }
  return eResult == E_AR_SUCCESS;
}

// 短线程
void WnTCPClient::OnConnectThread(int nStatus)
{
  readLock lock(m_oNotifyMutex);
  if(m_poNotify != NULL)
    m_poNotify->OnConnectServer(nStatus);
}

// 短线程
void WnTCPClient::OnDisconnectThread(int nStatus)
{
  readLock lock(m_oNotifyMutex);
  if(m_poNotify != NULL)
    m_poNotify->OnServerDisconnect(nStatus);
}

void WnTCPClient::OnDataErrorThread()
{
  readLock lock(m_oNotifyMutex);
  if(m_poNotify != NULL)
    m_poNotify->OnServerDataError();
}

void WnTCPClient::OnConnectTimeOutTimer(const boost::system::error_code& oErrorCode)
{
  if(!oErrorCode && m_apConnection)
  {
    m_apConnection->Close();
    OnConnect(m_apConnection, E_CONNECT_TIMEOUT);
  }
}

void WnTCPClient::OnNoRecvDataTimer(const boost::system::error_code& oErrorCode)
{
  if(!oErrorCode && m_apConnection)
  {
    // 关闭连接
    m_apConnection->Close();

    // 发出通知
    OnDisconnect(m_apConnection, E_DISCONNECT_RCVTIMEOUT);
  }
}

void WnTCPClient::OnMsg(int type, const std::string& msg)
{
  readLock lock(m_oNotifyMutex);
  if(nullptr != m_poNotify)
    m_poNotify->OnTCPMsg(type, msg);
}

void WnTCPClient::RegisterSpi(ITCPClientNotify *pSpi)
{
  writeLock lock(m_oNotifyMutex);
  m_poNotify = pSpi;
}

void WnTCPClient::ConnectOtherServer(const char *szIP, unsigned short usPort, bool blAuth /*= false*/, unsigned int unTimeOut /*= 0*/)
{

}

bool WnTCPClient::SendDataToOtherServer(const unsigned char *pbData, unsigned int unDataSize)
{
  return false;
}

extern "C"
{
  boost::mutex gMutex_Client;

  /// \brief 通信终端表
  LIST_END_POINT gEndPointList_Client;

  int gID_Client = 0;

  ITCPClient* CreateTCPClientInstance(ITCPClientNotify* poNotifyObj, int HBInterval , unsigned short usThreadCount /* = 0 */)
  {
    boost::mutex::scoped_lock oGlobalLock(gMutex_Client);
    WnTCPClient* pObj = new WnTCPClient(++gID_Client, poNotifyObj, HBInterval, usThreadCount);
    gEndPointList_Client.push_back(END_POINT_APTR(pObj));
    return pObj;
  }

  void ReleaseTCPClientInstance(ITCPClient* poClientInstance)
  {
    boost::mutex::scoped_lock oGlobalLock(gMutex_Client);

    poClientInstance->CloseSocket();
    for(auto it = gEndPointList_Client.begin(); it != gEndPointList_Client.end(); ++it)
    {
      if((*it)->GetID() == static_cast<WnTCPClient*>(poClientInstance)->GetID())
      {
        gEndPointList_Client.erase(it);
        break;
      }
    }
  }
}